package com.example.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 在 LockConditionPrintABCService 中使用 while 循环而不是 if 判断，是为了防止 虚假唤醒 问题。
 * <p>
 * 什么是虚假唤醒？
 * 虚假唤醒（Spurious Wakeup）是指一个线程在没有被显式唤醒的情况下从 await()、wait() 等方法返回。虚假唤醒是可能发生的，因为操作系统和 JVM 的实现细节可能会导致线程在没有接收到信号的情况下被唤醒。
 * <p>
 * 为什么要用 while 而不是 if？
 * 假设你使用的是 if 语句，线程被唤醒后只会检查条件一次。如果发生了虚假唤醒，条件可能并未被满足，但线程会继续执行，导致程序逻辑错误。
 * <p>
 * 而使用 while 循环，线程被唤醒后会反复检查条件，直到条件满足为止。这样即使发生虚假唤醒，线程依然会回到等待状态，保证程序逻辑的正确性。
 * <p>
 * 示例代码中的情况
 * 在 LockConditionPrintABCService 中，while (state != 0) 这段代码是在 printA 方法中等待 state 到达合适的值，确保当前线程执行的任务是正确的。如果这里使用 if 而不是 while：
 * <p>
 * if (state != 0) {
 * conditionA.await(); // 等待被唤醒
 * }
 * 一旦线程被唤醒，它只会检查条件一次，可能会因为虚假唤醒导致 state 还不在预期的范围内，但线程依然继续执行。这会破坏线程之间的协作，导致打印顺序错误。而使用 while 循环，即使线程被虚假唤醒，它仍会不断检查条件，确保 state 处于正确状态，避免程序逻辑错误。
 * <p>
 * 结论
 * while 循环的使用是为了确保条件在每次唤醒时都被正确地检查，以避免虚假唤醒带来的问题，这是多线程编程中的一个常见最佳实践。
 */
@Service
@Slf4j
public class ReentrantLockPrintABCService {

    private final Lock lock = new ReentrantLock();
    private final Condition conditionA = lock.newCondition();
    private final Condition conditionB = lock.newCondition();
    private final Condition conditionC = lock.newCondition();
    private int state = 0; // 0 表示 A, 1 表示 B, 2 表示 C
    private static final int TOTAL_CYCLES = 5; // 总循环次数

    public void printABCSequence() {
        Thread threadA = new Thread(this::printA);
        Thread threadB = new Thread(this::printB);
        Thread threadC = new Thread(this::printC);

        threadA.start();
        threadB.start();
        threadC.start();

        try {
            threadA.join();
            threadB.join();
            threadC.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("主线程被中断", e);
        }

        log.info("所有循环已完成，任务结束");
    }

    private void printA() {
        for (int cycle = 0; cycle < TOTAL_CYCLES; cycle++) {
            lock.lock();
            try {
                while (state != 0) {
                    conditionA.await(); // 等待A的执行条件
                }
                for (int i = 0; i < 3; i++) {
                    log.info("A");
                }
                state = 1; // 切换到B
                conditionB.signal(); // 唤醒B线程
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("线程A被中断", e);
            } finally {
                lock.unlock();
            }
        }
    }

    private void printB() {
        for (int cycle = 0; cycle < TOTAL_CYCLES; cycle++) {
            lock.lock();
            try {
                while (state != 1) {
                    conditionB.await(); // 等待B的执行条件
                }
                for (int i = 0; i < 2; i++) {
                    log.info("B");
                }
                state = 2; // 切换到C
                conditionC.signal(); // 唤醒C线程
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("线程B被中断", e);
            } finally {
                lock.unlock();
            }
        }
    }

    private void printC() {
        for (int cycle = 0; cycle < TOTAL_CYCLES; cycle++) {
            lock.lock();
            try {
                while (state != 2) {
                    conditionC.await(); // 等待C的执行条件
                }
                log.info("C");
                state = 0; // 重置为A的状态
                conditionA.signal(); // 唤醒A线程
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("线程C被中断", e);
            } finally {
                lock.unlock();
            }
        }
    }
}
